<template>
  <div>
    <router-view v-slot="{ Component }">
      <!-- 因为不同的name 会执行不同的动画效果
       当我们进入一个新页面的时候,name变成push 执行新页面跳转动画
       当我们返回一个旧页面的时候,name变成back 执行返回动画 -->
      <transition
        @before-enter="beforeEnter"
        @after-leave="afterLeave"
        :name="transitionName"
      >

        <keep-alive :include="virtualTaskStack">
      
          <component :is="Component" :class="{ ding: isAnimate }"/>
        </keep-alive>
      </transition>
    </router-view>
  </div>
</template>

<script>
//常量通常是大写，定义一些不变的变量。
const ROUTER_TYPE_PUSH = "push";
const ROUTER_TYPE_BACK = "back";
const NONE = "none";
const ROUTER_TYPE_ENUM = [ROUTER_TYPE_PUSH, ROUTER_TYPE_BACK, NONE];
//因为要做成一个通用的组件，判断当前你的组件使用是否正确
</script>
<script setup>
import { defineProps } from "vue";
//需要做一个标记，标记你是新页面，要执行push动画
//需要另外的一个标记，表明你是返回旧页面，执行back动画
let props = defineProps({
  //如果routerType push  back
  //路由跳转的类型：push 是进入组件 back是退出组件
  routerType: {
    type: String,
    default: NONE,
    validator(val) {
      //如果我们在设置跳转的过程中没有设置push 或者back 提示开发者，你要设置
      //保证开发者一定要传递这个routerType，且routerType是push 或者 back 或者none
      const result = ROUTER_TYPE_ENUM.includes(val);
      if (!result) {
        //routerType 的值不是push back none 三者之一 ，提示错误信息
        //抛出异常
        throw new Error(`你的router_type必须是ROUTER_TYPE_ENUM的其中一个`);
      }
      return result;
    },
  },
  //接收显示的组件，也是任务栈中第一个组件
  mainComponentName: {
    type: String,
    required: true,
  },
});
import { ref } from "vue";
import { useRouter } from "vue-router";
let transitionName = ref("");
let router = useRouter();
//在路由守卫中设置动画名称
router.beforeEach((to) => {
  //to是即将跳转的目的路由
  transitionName.value = props.routerType; //back
  //进栈出栈操作 【home,my】
  if (props.routerType === ROUTER_TYPE_PUSH) {
    // 进栈的操作
    virtualTaskStack.value.push(to.name);
  } else if (props.routerType === ROUTER_TYPE_BACK) {
    // 出栈的操作
    virtualTaskStack.value.pop();
  }
  if (to.name === props.mainComponentName) {
    //跳回首页  清空任务栈的操作=>就是把数组重置
    clearTask();
  }
});

//isAimate 控制动画执行
let isAnimate = ref(false);
const beforeEnter = () => {

  isAnimate.value = true;
};
const afterLeave = () => {
 
  isAnimate.value = false;
};

//初始化空的任务栈 =>先把首页放在初始化数组中
let virtualTaskStack = ref([props.mainComponentName]);
//定义重置的任务栈方法
const clearTask = () => {
  virtualTaskStack.value = [props.mainComponentName];
};
</script>

<style lang="scss" scoped>
.ding {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  z-index: 99;
}
// push页面时：新页面的进入动画
.push-enter-active {
  animation-name: push-in;
  animation-duration: 0.4s;
}
// push页面时：老页面的退出动画
.push-leave-active {
  animation-name: push-out;
  animation-duration: 0.4s;
}
// push页面时：新页面的进入动画
@keyframes push-in {
  0% {
    transform: translate(100%, 0);
  }
  100% {
    transform: translate(0, 0);
  }
}
// push页面时：老页面的退出动画
@keyframes push-out {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(-50%, 0);
  }
}

// 后退页面时：即将展示的页面动画
.back-enter-active {
  animation-name: back-in;
  animation-duration: 0.4s;
}
// 后退页面时：后退的页面执行的动画
.back-leave-active {
  animation-name: back-out;
  animation-duration: 0.4s;
}
// 后退页面时：即将展示的页面动画
@keyframes back-in {
  0% {
    width: 100%;
    transform: translate(-100%, 0);
  }
  100% {
    width: 100%;
    transform: translate(0, 0);
  }
}
// 后退页面时：后退的页面执行的动画
@keyframes back-out {
  0% {
    width: 100%;
    transform: translate(0, 0);
  }
  100% {
    width: 100%;
    transform: translate(50%, 0);
  }
}
</style>
